﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using CMPPProtocol.Message;

namespace CMPPProtocol
{
    /// <summary>
    /// CMPP2协议策略
    /// </summary>
    public class CMPP2Protocol : BaseCMPPProtocol
    {
        public const byte CMMPPVersion = 0x20;

        /// <summary>
        /// 获取“数据包”的字节流。
        /// </summary>
        internal override byte[] GetBytes(ICMPP_Protocol message)
        {
            Type msgType = message.GetType();

            #region CMPP_CONNECT
            if (msgType == typeof(CMPP_CONNECT))
            {
                CMPP_CONNECT msg = message as CMPP_CONNECT;
                msg.Version = CMPP2Protocol.CMMPPVersion;
            }
            #endregion

            #region CMPP_SUBMIT

            if (msgType == typeof(CMPP_SUBMIT))
            {
                byte[] buffer = null;
                Byte[] temp = null;
                int iPos = 0;
                bool isLongSubmit = false;
                CMPP_SUBMIT msg = message as CMPP_SUBMIT;



                if (msg.PkTotal > 1)
                {
                    isLongSubmit = true;
                    msg.MsgFmt = (byte)CMPPEncoding.CODING_UCS2;
                    msg.TPUdhi = 1;
                }



                msg.Head.TotalLength = (UInt32)(138 + 21 * msg.DestUsrTl + msg.MsgLength);

                if (isLongSubmit)
                {
                    msg.Head.TotalLength += 6;
                }
                buffer = new Byte[msg.Head.TotalLength];


                temp = this.GetBytes(msg.Head);
                temp.CopyTo(buffer, iPos);
                iPos += temp.Length;

                temp = BitConverter.GetBytes(msg.MsgID);
                temp.CopyTo(buffer, iPos);
                iPos += temp.Length;


                buffer[iPos] = 1;//PkTotal
                iPos++;

                buffer[iPos] = 1;//PkNumber
                iPos++;

                buffer[iPos] = msg.RegisteredDelivery;
                iPos++;

                buffer[iPos] = msg.MsgLevel;
                iPos++;


                temp = Convert.ToBytes(msg.ServiceID, CMPPEncoding.CODING_ASCII);
                temp.CopyTo(buffer, iPos);
                iPos += 10;


                buffer[iPos] = msg.FeeUserType;
                iPos++;

                temp = Convert.ToBytes(msg.FeeTerminalID, CMPPEncoding.CODING_ASCII);
                temp.CopyTo(buffer, iPos);
                iPos += 21;

                buffer[iPos] = msg.TPPID;
                iPos++;

                buffer[iPos] = msg.TPUdhi;
                iPos++;

                buffer[iPos] = msg.MsgFmt;
                iPos++;


                temp = Convert.ToBytes(msg.MsgSrc, CMPPEncoding.CODING_ASCII);
                temp.CopyTo(buffer, iPos);
                iPos += 6;

                temp = Convert.ToBytes(msg.FeeType, CMPPEncoding.CODING_ASCII);
                temp.CopyTo(buffer, iPos);
                iPos += 2;

                temp = Convert.ToBytes(msg.FeeCode, CMPPEncoding.CODING_ASCII);
                temp.CopyTo(buffer, iPos);
                iPos += 6;

                temp = Convert.ToBytes(msg.ValidTime, CMPPEncoding.CODING_ASCII);
                temp.CopyTo(buffer, iPos);
                iPos += 17;

                temp = Convert.ToBytes(msg.AtTime, CMPPEncoding.CODING_ASCII);
                temp.CopyTo(buffer, iPos);
                iPos += 17;


                temp = Convert.ToBytes(msg.SrcID, CMPPEncoding.CODING_ASCII);
                temp.CopyTo(buffer, iPos);
                iPos += 21;


                buffer[iPos] = msg.DestUsrTl;
                iPos++;

                for (int i = 0; i < msg.DestUsrTl; i++)
                {
                    temp = Convert.ToBytes(msg.DestTerminalID[i], CMPPEncoding.CODING_ASCII);
                    temp.CopyTo(buffer, iPos);
                    iPos = iPos + 21;
                }


                buffer[iPos] = msg.MsgLength;
                if (isLongSubmit)
                {
                    buffer[iPos] += 6;
                }
                iPos++;


                if (isLongSubmit)
                {
                    buffer[iPos] = 5;
                    iPos++;
                    buffer[iPos] = 0;
                    iPos++;
                    buffer[iPos] = 3;
                    iPos++;
                    buffer[iPos] = 1;
                    iPos++;
                    buffer[iPos] = msg.PkTotal;
                    iPos++;
                    buffer[iPos] = msg.PkNumber;
                    iPos++;
                }

                temp = Convert.ToBytes(msg.MsgContent, (CMPPEncoding)msg.MsgFmt);
                temp.CopyTo(buffer, iPos);
                iPos += temp.Length;

                iPos += 8;

                if (iPos != msg.Head.TotalLength)
                {
                    throw new MessageException(msg,"消息格式不正确");
                }
                return buffer;
            }

            #endregion

            return base.GetBytes(message);
        }

        internal override T FromBytes<T>(byte[] buffer)
        {
            Type msgType = typeof(T);
            T t = base.FromBytes<T>(buffer);
            
            #region CMPP_CONNECT_RESP

            if (msgType == typeof(CMPP_CONNECT_RESP))
            {
                CMPP_CONNECT_RESP msg = t as CMPP_CONNECT_RESP;
                byte[] temp = new byte[1];
                Array.Copy(buffer, temp, temp.Length);

                Array.Reverse(temp);
                msg.Status = (uint)buffer[0];


                msg.AuthenticatorISMG = new byte[16];
                Array.Copy(buffer, 1, msg.AuthenticatorISMG, 0, 16);
                msg.Version = buffer[17];
            }

            #endregion

            #region CMPP_DELIVER

            if (msgType == typeof(CMPP_DELIVER))
            {
                CMPP_DELIVER msg = t as CMPP_DELIVER;
                byte[] temp;
                int iPos = 0;
                temp = new byte[8];
                Array.Copy(buffer, temp, temp.Length);
                msg.MsgID = BitConverter.ToUInt64(temp, 0);
                iPos += temp.Length;

                temp = new byte[21];
                Array.Copy(buffer, iPos, temp, 0, temp.Length);
                msg.DestID = Convert.ToString(temp, 0, temp.Length, CMPPEncoding.CODING_ASCII);
                iPos = iPos + temp.Length;


                temp = new byte[10];
                Array.Copy(buffer, iPos, temp, 0, temp.Length);
                msg.ServiceID = Convert.ToString(temp, 0, temp.Length, CMPPEncoding.CODING_ASCII);
                iPos = iPos + temp.Length;


                msg.TPPID = buffer[iPos];
                iPos++;

                msg.TPUdhi = buffer[iPos];
                iPos++;

                msg.MsgFmt = buffer[iPos];
                iPos++;

                temp = new byte[21];
                Array.Copy(buffer, iPos, temp, 0, temp.Length);
                msg.SrcTerminalID = Convert.ToString(temp, 0, temp.Length, CMPPEncoding.CODING_ASCII);
                iPos = iPos + temp.Length;


                msg.RegisteredDelivery = buffer[iPos];
                iPos++;

                msg.MsgLength = buffer[iPos];
                iPos++;


                if (msg.RegisteredDelivery == 0)//是短消息
                {
                    if (buffer[iPos] == 5 && buffer[iPos + 1] == 0 && buffer[iPos + 2] == 3)
                    {
                        iPos++;
                        iPos++;
                        iPos++;
                        msg.PkSequence = buffer[iPos];
                        iPos++;
                        msg.PkTotal = buffer[iPos];
                        iPos++;
                        msg.PkNumber = buffer[iPos];
                        iPos++;

                        msg.MsgLength -= 6;
                    }

                    msg.MsgContent = Convert.ToString(buffer, iPos, msg.MsgLength, (CMPPEncoding)msg.MsgFmt);

                }
                else//是状态报告,先转为BASE64 String 存储
                    msg.MsgContent = System.Convert.ToBase64String(buffer, iPos, msg.MsgLength);



                if (msg.RegisteredDelivery == 1)
                {
                    Byte[] bytes = System.Convert.FromBase64String(msg.MsgContent);
                    if ((bytes != null) && (bytes.Length > 0))
                    {
                        msg.Report= this.FromBytes<CMPP_REPORT>(bytes);
                    }
                }


            }

            #endregion

            #region CMPP_REPORT

            if (msgType == typeof(CMPP_REPORT))
            {
                CMPP_REPORT msg = t as CMPP_REPORT;
                byte[] temp;
                int iPos=0;
                temp = new byte[8];
                Array.Copy(buffer, temp, temp.Length);
                msg.MsgID = BitConverter.ToUInt64(temp, 0);
                iPos = iPos + temp.Length;


                temp = new byte[7];
                Array.Copy(buffer, iPos, temp, 0, temp.Length);
                msg.Stat = Convert.ToString(temp, 0, temp.Length, CMPPEncoding.CODING_ASCII);
                iPos = iPos + temp.Length;


                temp = new byte[10];
                Array.Copy(buffer, iPos, temp, 0, temp.Length);
                msg.SubmitTime = Convert.ToString(temp, 0, temp.Length, CMPPEncoding.CODING_ASCII);
                iPos = iPos + temp.Length;


                temp = new byte[10];
                Array.Copy(buffer, iPos, temp, 0, temp.Length);
                msg.DoneTime = Convert.ToString(temp, 0, temp.Length, CMPPEncoding.CODING_ASCII);
                iPos = iPos + temp.Length;


                temp = new byte[21];
                Array.Copy(buffer, iPos, temp, 0, temp.Length);
                msg.DestTerminalID = Convert.ToString(temp, 0, temp.Length, CMPPEncoding.CODING_ASCII);
                iPos = iPos + temp.Length;

                temp = new byte[4];
                Array.Copy(buffer, iPos, temp, 0, temp.Length);
                Array.Reverse(temp);
                msg.SMSCSequence= (uint)BitConverter.ToInt32(temp, 0);

            }

            #endregion

            #region CMPP_SUBMIT_RESP

            if (msgType == typeof(CMPP_SUBMIT_RESP))
            {
                CMPP_SUBMIT_RESP msg = t as CMPP_SUBMIT_RESP;
                byte[] temp;
                int iPos = 0;
                temp = new byte[8];
                Array.Copy(buffer, temp, temp.Length);
                msg.MsgID = (UInt64)BitConverter.ToUInt64(temp, 0);
                iPos += temp.Length;

                temp = new byte[1];
                Array.Copy(buffer, iPos, temp, 0, temp.Length);
                msg.Result = (uint)temp[0];
            }

            #endregion

            #region CMPP_CANCEL_RESP
            if (msgType == typeof(CMPP_CANCEL_RESP))
            {
                CMPP_CANCEL_RESP msg = t as CMPP_CANCEL_RESP;
                msg.SuccessID = (uint)buffer[0];
            }
            #endregion
            return t;
        }
    }
}
